package com.suke.widget;

import com.suke.widget.attrs.SwitchAttrSet;
import com.suke.widget.utils.AttrUtils;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.render.Arc;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.multimodalinput.event.TouchEvent;

/**
 * SwitchButton.
 */
public class SwitchButton extends Button implements Checkable, Component.DrawTask, Component.LayoutRefreshedListener, Component.EstimateSizeListener, Component.TouchEventListener {
    private static final HiLogLabel LOG_LABEL = new HiLogLabel(HiLog.LOG_APP, 0x20221, "SwitchButton");
    private final int DEFAULT_WIDTH = dp2pxInt(58);
    private final int DEFAULT_HEIGHT = dp2pxInt(36);

    /**
     * 动画状态：
     * 1.静止
     * 2.进入拖动
     * 3.处于拖动
     * 4.拖动-复位
     * 5.拖动-切换
     * 6.点击切换
     **/
    private final int ANIMATE_STATE_NONE = 0;
    private final int ANIMATE_STATE_PENDING_DRAG = 1;
    private final int ANIMATE_STATE_DRAGING = 2;
    private final int ANIMATE_STATE_PENDING_RESET = 3;
    private final int ANIMATE_STATE_PENDING_SETTLE = 4;
    private final int ANIMATE_STATE_SWITCH = 5;
    private int buttonColor;
    private int effectDuration;

    public SwitchButton(Context context) {
        super(context);
        init(context, null);
    }

    public SwitchButton(Context context, AttrSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public SwitchButton(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @Override
    public final void setPadding(int left, int top, int right, int bottom) {
        super.setPadding(0, 0, 0, 0);
    }

    private void init(Context context, AttrSet attrs) {
        initAttrs(context,attrs);
        paint = new Paint();
        buttonPaint = new Paint();
        buttonPaint.setColor(new Color(buttonColor));

        viewState = new ViewState();
        beforeState = new ViewState();
        afterState = new ViewState();

        valueAnimator = new AnimatorValue();
        valueAnimator.setDuration(effectDuration);
        valueAnimator.setLoopedCount(0);

        valueAnimator.setValueUpdateListener(animatorUpdateListener);
        valueAnimator.setStateChangedListener(animatorListener);

        super.setClickable(true);
        this.setPadding(0, 0, 0, 0);
        setEstimateSizeListener(this);
        setLayoutRefreshedListener(this);
        setTouchEventListener(this);
        addDrawTask(this);
        HiLog.info(LOG_LABEL, "ischecked : " + isChecked());
        if (!isUiInited) {
            onRefreshed(this);
        }
    }

    private  void initAttrs(Context context,AttrSet attrs){
        shadowEffect = AttrUtils.getBooleanFromAttr(attrs, SwitchAttrSet.SHADOW_EFFECT, true);
        uncheckCircleColor = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.UNCHECK_CICLE_COLOR, 0xffAAAAAA);
        uncheckCircleWidth = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.UNCHECK_CICLE_WIDTH, dp2pxInt(1.5f));
        uncheckCircleRadius = AttrUtils.getFloatFromAttr(attrs, SwitchAttrSet.UNCHECK_CICLE_RADIUS, dp2px(4));

        shadowRadius = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.SHADOW_RADIUS, dp2pxInt(2.5f));
        shadowOffset = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.SHADOW_OFFSET, dp2pxInt(1.5f));

        shadowColor = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.SHADOW_COLOR, 0x33000000);
        uncheckColor = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.UNCHECK_COLOR, 0xffDDDDDD);
        checkedColor = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.CHECK_COLOR, 0xff51d367);
        borderWidth = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.BORDER_WIDTH, dp2pxInt(1));
        checkLineColor = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.CHECK_LINE_COLOR, Color.WHITE.getValue());

        checkLineWidth = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.CHECK_LINE_WIDTH, dp2pxInt(1));

        buttonColor = AttrUtils.getColorFromAttr(attrs, SwitchAttrSet.BUTTON_COLOR, Color.WHITE.getValue());

        uncheckButtonColor = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.UNCHECK_BUTTON_COLOR, buttonColor);
        checkedButtonColor = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.CHECKED_BUTTON_COLOR, buttonColor);

        effectDuration = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.EFFECT_DURATION, 300);
        isChecked = AttrUtils.getBooleanFromAttr(attrs, SwitchAttrSet.CHECKED, false);
        showIndicator = AttrUtils.getBooleanFromAttr(attrs, SwitchAttrSet.SHOW_INDICATOR, true);
        enableEffect = AttrUtils.getBooleanFromAttr(attrs, SwitchAttrSet.ENABLE_EFFECT, true);
        background = AttrUtils.getIntFromAttr(attrs, SwitchAttrSet.BACKGROUND, Color.WHITE.getValue());
        uncheckCircleOffsetX = dp2px(10);

        checkedLineOffsetX = dp2px(4);
        checkedLineOffsetY = dp2px(4);

        checkLineLength = dp2px(6);
    }

    @Override
    public boolean onEstimateSize(int widthEstimateConfig, int heightEstimateConfig) {
        HiLog.info(LOG_LABEL, "onEstimateSize############");
        final int widthMode = EstimateSpec.getMode(widthEstimateConfig);
        final int heightMode = EstimateSpec.getMode(heightEstimateConfig);

        if (widthMode == EstimateSpec.UNCONSTRAINT
                || widthMode == EstimateSpec.NOT_EXCEED) {
            widthEstimateConfig = EstimateSpec.getSizeWithMode(DEFAULT_WIDTH, EstimateSpec.PRECISE);
        }
        if (heightMode == EstimateSpec.UNCONSTRAINT
                || heightMode == EstimateSpec.NOT_EXCEED) {
            heightEstimateConfig = EstimateSpec.getSizeWithMode(DEFAULT_HEIGHT, EstimateSpec.PRECISE);
        }
        HiLog.info(LOG_LABEL, "widthEstimateConfig : " + widthEstimateConfig + ",heightEstimateConfig :" + heightEstimateConfig);
        return true;
    }

    @Override
    public void onRefreshed(Component component) {
        HiLog.info(LOG_LABEL, "getEstimatedWidth:" + component.getEstimatedWidth());
        HiLog.info(LOG_LABEL, "getWidth:" + component.getWidth());

        int height = component.getHeight();
        int width = component.getWidth();

        float viewPadding = Math.max(shadowRadius + shadowOffset, borderWidth);
        this.height = height - viewPadding - viewPadding;
        this.width = width - viewPadding - viewPadding;

        viewRadius = this.height * .5f;
        buttonRadius = viewRadius - borderWidth;

        left = viewPadding;
        top = viewPadding;
        right = width - viewPadding;
        bottom = height - viewPadding;

        centerX = (left + right) * .5f;
        centerY = (top + bottom) * .5f;

        buttonMinX = left + viewRadius;
        buttonMaxX = right - viewRadius;

        if (isChecked()) {
            setCheckedViewState(viewState);
        } else {
            setUncheckViewState(viewState);
        }

        isUiInited = true;
//        invalidate();
    }


    private void setUncheckViewState(ViewState viewState) {
        viewState.radius = 0;
        viewState.checkStateColor = uncheckColor;
        viewState.checkedLineColor = Color.TRANSPARENT.getValue();
        viewState.buttonX = buttonMinX;
        buttonPaint.setColor(new Color(uncheckButtonColor));
        invalidate();
    }

    private void setCheckedViewState(ViewState viewState) {
        viewState.radius = viewRadius;
        HiLog.info(LOG_LABEL, "setCheckedViewState:checkedColor ===" + checkedColor);
        viewState.checkStateColor = checkedColor;
        viewState.checkedLineColor = checkLineColor;
        viewState.buttonX = buttonMaxX;
        buttonPaint.setColor(new Color(checkedButtonColor));
    }


    /**
     * 绘制选中状态指示器
     *
     * @param canvas
     */
    private void drawCheckedIndicator(Canvas canvas) {
        drawCheckedIndicator(canvas,
                viewState.checkedLineColor,
                checkLineWidth,
                left + viewRadius - checkedLineOffsetX, centerY - checkLineLength,
                left + viewRadius - checkedLineOffsetY, centerY + checkLineLength,
                paint);
    }


    /**
     * 绘制选中状态指示器
     *
     * @param canvas
     * @param color
     * @param lineWidth
     * @param sx
     * @param sy
     * @param ex
     * @param ey
     * @param paint
     */
    private void drawCheckedIndicator(Canvas canvas,
                                      int color,
                                      float lineWidth,
                                      float sx, float sy, float ex, float ey,
                                      Paint paint) {
        paint.setStyle(Paint.Style.STROKE_STYLE);
        paint.setColor(new Color(color));
        paint.setStrokeWidth(lineWidth);
        canvas.drawLine(new Point(sx, sy), new Point(ex, ey), paint);
    }

    /**
     * 绘制关闭状态指示器
     *
     * @param canvas
     */
    private void drawUncheckIndicator(Canvas canvas) {
        drawUncheckIndicator(canvas,
                uncheckCircleColor,
                uncheckCircleWidth,
                right - uncheckCircleOffsetX, centerY,
                uncheckCircleRadius,
                paint);
    }


    /**
     * 绘制关闭状态指示器
     *
     * @param canvas
     * @param color
     * @param lineWidth
     * @param centerX
     * @param centerY
     * @param radius
     * @param paint
     */
    protected void drawUncheckIndicator(Canvas canvas,
                                        int color,
                                        float lineWidth,
                                        float centerX, float centerY,
                                        float radius,
                                        Paint paint) {
        paint.setStyle(Paint.Style.STROKE_STYLE);
        paint.setColor(new Color(color));
        paint.setStrokeWidth(lineWidth);
        canvas.drawCircle(centerX, centerY, radius, paint);
    }

    private void drawArc(Canvas canvas,
                         float left, float top,
                         float right, float bottom,
                         float startAngle, float sweepAngle,
                         Paint paint) {
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//            canvas.drawArc(left, top, right, bottom,
//                    startAngle, sweepAngle, true, paint);
//        }else{
//            rect.set(left, top, right, bottom);
//            canvas.drawArc(rect,
//                    startAngle, sweepAngle, true, paint);
//        }
        mRectF = new RectFloat(left, top, right, bottom);
//        mRectF.translateTo(left, top);
        canvas.drawArc(mRectF, new Arc(startAngle, sweepAngle, true), paint);
    }

    private void drawRoundRect(Canvas canvas,
                               float left, float top,
                               float right, float bottom,
                               float backgroundRadius,
                               Paint paint) {
        HiLog.info(LOG_LABEL, "left:right:top:bottom:backgroundRadius:" + left + "," + right + "," + top + "," + bottom + "," + backgroundRadius);
        mRectF = new RectFloat(left, top, right, bottom);
//        mRectF.translateTo(left, top) ;
        canvas.drawRoundRect(mRectF, backgroundRadius, backgroundRadius, paint);
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//            canvas.drawRoundRect(left, top, right, bottom,
//                    backgroundRadius, backgroundRadius, paint);
//        }else{
//            rect.set(left, top, right, bottom);
//            canvas.drawRoundRect(rect,
//                    backgroundRadius, backgroundRadius, paint);
//        }
    }

    private void drawButton(Canvas canvas, float x, float y) {
        HiLog.info(LOG_LABEL, "x ===========" + x + ",y===============" + y);
        HiLog.info(LOG_LABEL, "buttonRadius : " + buttonRadius);
        canvas.drawCircle(x, y, buttonRadius, buttonPaint);

        paint.setStyle(Paint.Style.STROKE_STYLE);
        paint.setStrokeWidth(1);
        paint.setColor(new Color(0XffDDDDDD));
        canvas.drawCircle(x, y, buttonRadius, paint);
    }

    @Override
    public void setChecked(boolean checked) {
        HiLog.info(LOG_LABEL, "checked : " + checked);
        if (checked == isChecked()) {
            HiLog.info(LOG_LABEL, "setChecked return");
            invalidate();
            return;
        }
        HiLog.info(LOG_LABEL, "setChecked :" + checked);
        toggle(enableEffect, false);
    }

    @Override
    public boolean isChecked() {
        return isChecked;
    }

    @Override
    public void toggle() {
        toggle(true);
    }

    /**
     * 切换状态
     *
     * @param animate
     */
    public void toggle(boolean animate) {
        toggle(animate, true);
    }

    private void toggle(boolean animate, boolean broadcast) {
        if (!isEnabled()) {
            return;
        }

        if (isEventBroadcast) {
            throw new RuntimeException("should NOT switch the state in method: [onCheckedChanged]!");
        }
        if (!isUiInited) {
            HiLog.info(LOG_LABEL, "isUiInited == false ");
            isChecked = !isChecked;
            if (broadcast) {
                broadcastEvent();
            }
            return;
        }

        if (valueAnimator.isRunning()) {
            valueAnimator.cancel();
        }

        if (!enableEffect || !animate) {
            isChecked = !isChecked;
            if (isChecked()) {
                setCheckedViewState(viewState);
            } else {
                setUncheckViewState(viewState);
            }
            invalidate();
            if (broadcast) {
                broadcastEvent();
            }
            return;
        }

        animateState = ANIMATE_STATE_SWITCH;
        beforeState.copy(viewState);
        HiLog.info(LOG_LABEL, "change check status");
        if (isChecked()) {
            //切换到unchecked
            setUncheckViewState(afterState);
        } else {
            setCheckedViewState(afterState);
        }
        valueAnimator.start();
    }

    private void broadcastEvent() {
        if (onCheckedChangeListener != null) {
            isEventBroadcast = true;
            onCheckedChangeListener.onCheckedChanged(this, isChecked());
        }
        isEventBroadcast = false;
    }

    private boolean isInAnimating() {
        return animateState != ANIMATE_STATE_NONE;
    }

    private boolean isPendingDragState() {
        return animateState == ANIMATE_STATE_PENDING_DRAG
                || animateState == ANIMATE_STATE_PENDING_RESET;
    }

    private boolean isDragState() {
        return animateState == ANIMATE_STATE_DRAGING;
    }

    private void setShadowEffect(boolean shadowEffect) {
        if (this.shadowEffect == shadowEffect) {
            return;
        }
        this.shadowEffect = shadowEffect;
//        if(this.shadowEffect){
//            buttonPaint.setShadowLayer(
//                    shadowRadius,
//                    0, shadowOffset,
//                    shadowColor);
//        }else{
//            buttonPaint.setShadowLayer(
//                    0,
//                    0, 0,
//                    0);
//        }
    }

    /**
     * @param enable true:开启动画；false：关闭动画
     */
    public void setEnableEffect(boolean enable) {
        this.enableEffect = enable;
    }

    private void pendingDragState() {
        if (isInAnimating()) {
            return;
        }
        if (!isTouchingDown) {
            return;
        }

        if (valueAnimator.isRunning()) {
            valueAnimator.cancel();
        }

        animateState = ANIMATE_STATE_PENDING_DRAG;

        beforeState.copy(viewState);
        afterState.copy(viewState);

        if (isChecked()) {
            afterState.checkStateColor = checkedColor;
            afterState.buttonX = buttonMaxX;
            afterState.checkedLineColor = checkedColor;
        } else {
            afterState.checkStateColor = uncheckColor;
            afterState.buttonX = buttonMinX;
            afterState.radius = viewRadius;
        }

        valueAnimator.start();
    }


    /**
     * 取消拖动状态
     */
    private void pendingCancelDragState() {
        if (isDragState() || isPendingDragState()) {
            if (valueAnimator.isRunning()) {
                valueAnimator.cancel();
            }

            animateState = ANIMATE_STATE_PENDING_RESET;
            beforeState.copy(viewState);

            if (isChecked()) {
                setCheckedViewState(afterState);
            } else {
                setUncheckViewState(afterState);
            }
            valueAnimator.start();
        }
    }


    /**
     * 动画-设置新的状态
     */
    private void pendingSettleState() {
        if (valueAnimator.isRunning()) {
            valueAnimator.cancel();
        }

        animateState = ANIMATE_STATE_PENDING_SETTLE;
        beforeState.copy(viewState);

        if (isChecked()) {
            setCheckedViewState(afterState);
        } else {
            setUncheckViewState(afterState);
        }
        valueAnimator.start();
    }

    /**
     * @param listener 选中状态回调监听
     */
    public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
        onCheckedChangeListener = listener;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        HiLog.info(LOG_LABEL, "onDraw !!!!!!!!!!!!!");
        HiLog.info(LOG_LABEL, "borderWidth == " + borderWidth);
        paint.setStrokeWidth(borderWidth);
        paint.setStyle(Paint.Style.FILL_STYLE);
        //绘制白色背景
        paint.setColor(new Color(background));
        drawRoundRect(canvas,
                left, top, right, bottom,
                viewRadius, paint);
        //绘制关闭状态的边框
        paint.setStyle(Paint.Style.STROKE_STYLE);
        paint.setColor(new Color(uncheckColor));
        drawRoundRect(canvas,
                left, top, right, bottom,
                viewRadius, paint);

        //绘制小圆圈
        if (showIndicator) {
            drawUncheckIndicator(canvas);
        }

        //绘制开启背景色
        float des = viewState.radius * .5f;//[0-backgroundRadius*0.5f]
        paint.setStyle(Paint.Style.STROKE_STYLE);
        HiLog.info(LOG_LABEL, "viewState.checkStateColor : " + viewState.checkStateColor);
        HiLog.info(LOG_LABEL, "checkStateColor" + 0xfffdc951);
        paint.setColor(new Color(viewState.checkStateColor));
        paint.setStrokeWidth(borderWidth + des * 2f);
        drawRoundRect(canvas,
                left + des, top + des, right - des, bottom - des,
                viewRadius, paint);

        //绘制按钮左边绿色长条遮挡
        paint.setStyle(Paint.Style.FILL_STYLE);
        paint.setStrokeWidth(1);
        drawArc(canvas,
                left, top,
                left + 2 * viewRadius, top + 2 * viewRadius,
                90, 180, paint);
        canvas.drawRect(new RectFloat(left + viewRadius, top,
                        viewState.buttonX, top + 2 * viewRadius), paint);

        //绘制小线条
        if (showIndicator) {
            drawCheckedIndicator(canvas);
        }

        //绘制按钮
        drawButton(canvas, viewState.buttonX, centerY);
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (!isEnabled()) {
            return false;
        }
        int actionMasked = touchEvent.getAction();

        switch (actionMasked) {
            case TouchEvent.PRIMARY_POINT_DOWN: {
                isTouchingDown = true;
                touchDownTime = System.currentTimeMillis();
                //取消准备进入拖动状态
                mPendingDragHandle.removeTask(postPendingDrag);
                mPendingDragHandle.postTask(postPendingDrag, 100);
//                removeCallbacks(postPendingDrag);
                //预设100ms进入拖动状态
//                postDelayed(postPendingDrag, 100);
                break;
            }
            case TouchEvent.POINT_MOVE: {
                float eventX = touchEvent.getPointerScreenPosition(0).getX();
                if (isPendingDragState()) {
                    //在准备进入拖动状态过程中，可以拖动按钮位置
                    float fraction = eventX / getWidth();
                    fraction = Math.max(0f, Math.min(1f, fraction));

                    viewState.buttonX = buttonMinX
                            + (buttonMaxX - buttonMinX)
                            * fraction;

                } else if (isDragState()) {
                    //拖动按钮位置，同时改变对应的背景颜色
                    float fraction = eventX / getWidth();
                    fraction = Math.max(0f, Math.min(1f, fraction));

                    viewState.buttonX = buttonMinX
                            + (buttonMaxX - buttonMinX)
                            * fraction;

//                    viewState.checkStateColor = (int) argbEvaluator.evaluate(
//                            fraction,
//                            uncheckColor,
//                            checkedColor
//                    );
                    invalidate();

                }
                break;
            }
            case TouchEvent.PRIMARY_POINT_UP: {
                isTouchingDown = false;
                //取消准备进入拖动状态
                mPendingDragHandle.removeTask(postPendingDrag);
//                removeCallbacks(postPendingDrag);

                if (System.currentTimeMillis() - touchDownTime <= 300) {
                    //点击时间小于300ms，认为是点击操作
                    toggle();
                } else if (isDragState()) {
                    //在拖动状态，计算按钮位置，设置是否切换状态
                    float eventX = touchEvent.getPointerScreenPosition(0).getX();
                    float fraction = eventX / getWidth();
                    fraction = Math.max(0f, Math.min(1f, fraction));
                    boolean newCheck = fraction > .5f;
                    if (newCheck == isChecked()) {
                        pendingCancelDragState();
                    } else {
                        isChecked = newCheck;
                        pendingSettleState();
                    }
                } else if (isPendingDragState()) {
                    //在准备进入拖动状态过程中，取消之，复位
                    pendingCancelDragState();
                }
                break;
            }
            case TouchEvent.CANCEL: {
                isTouchingDown = false;
                mPendingDragHandle.removeTask(postPendingDrag);
//                removeCallbacks(postPendingDrag);

                if (isPendingDragState()
                        || isDragState()) {
                    //复位
                    pendingCancelDragState();
                }
                break;
            }
        }
        return true;
    }


    public interface OnCheckedChangeListener {
        void onCheckedChanged(SwitchButton view, boolean isChecked);
    }


    private float dp2px(float dp) {
        return (dp * getResourceManager().getDeviceCapability().screenDensity / 160);
    }

    private int dp2pxInt(float dp) {
        return (int) dp2px(dp);
    }


    /**
     * 阴影半径
     */
    private int shadowRadius;
    /**
     * 阴影Y偏移px
     */
    private int shadowOffset;
    /**
     * 阴影颜色
     */
    private int shadowColor;

    /**
     * 背景半径
     */
    private float viewRadius;
    /**
     * 按钮半径
     */
    private float buttonRadius;

    /**
     * 背景高
     */
    private float height;
    /**
     * 背景宽
     */
    private float width;
    /**
     * 背景位置
     */
    private float left;
    private float top;
    private float right;
    private float bottom;
    private float centerX;
    private float centerY;

    /**
     * 背景底色
     */
    private int background;
    /**
     * 背景关闭颜色
     */
    private int uncheckColor;
    /**
     * 背景打开颜色
     */
    private int checkedColor;
    /**
     * 边框宽度px
     */
    private int borderWidth;

    /**
     * 打开指示线颜色
     */
    private int checkLineColor;
    /**
     * 打开指示线宽
     */
    private int checkLineWidth;
    /**
     * 打开指示线长
     */
    private float checkLineLength;
    /**
     * 关闭圆圈颜色
     */
    private int uncheckCircleColor;
    /**
     * 关闭圆圈线宽
     */
    private int uncheckCircleWidth;
    /**
     * 关闭圆圈位移X
     */
    private float uncheckCircleOffsetX;
    /**
     * 关闭圆圈半径
     */
    private float uncheckCircleRadius;
    /**
     * 打开指示线位移X
     */
    private float checkedLineOffsetX;
    /**
     * 打开指示线位移Y
     */
    private float checkedLineOffsetY;
    /**
     * Color for button when it's uncheck
     */
    private int uncheckButtonColor;
    /**
     * Color for button when it's check
     */
    private int checkedButtonColor;


    /**
     * 按钮最左边
     */
    private float buttonMinX;
    /**
     * 按钮最右边
     */
    private float buttonMaxX;

    /**
     * 按钮画笔
     */
    private Paint buttonPaint;
    /**
     * 背景画笔
     */
    private Paint paint;

    /**
     * 当前状态
     */
    private ViewState viewState;
    private ViewState beforeState;
    private ViewState afterState;

    private RectFloat mRectF = new RectFloat();
    /**
     * 动画状态
     */
    private int animateState = ANIMATE_STATE_NONE;

    /**
     *
     */
    private AnimatorValue valueAnimator;

    /**
     * 是否选中
     */
    private boolean isChecked;

    /**
     * 是否启用动画
     */
    private boolean enableEffect;

    /**
     * 是否启用阴影效果
     */
    private boolean shadowEffect;

    /**
     * 是否显示指示器
     */
    private boolean showIndicator;


    /**
     * 手势是否按下
     */
    private boolean isTouchingDown = false;

    private boolean isUiInited = false;

    private boolean isEventBroadcast = false;

    private OnCheckedChangeListener onCheckedChangeListener;

    /**
     * 手势按下的时刻
     */
    private long touchDownTime;

    private Runnable postPendingDrag = new Runnable() {
        @Override
        public void run() {
            if (!isInAnimating()) {
                pendingDragState();
            }
        }
    };

    private EventHandler mPendingDragHandle =
            new EventHandler(EventRunner.getMainEventRunner()) {
                @Override
                protected void processEvent(InnerEvent event) {

                }
            };
    private AnimatorValue.ValueUpdateListener animatorUpdateListener
            = new AnimatorValue.ValueUpdateListener() {
        @Override
        public void onUpdate(AnimatorValue animatorValue, float value) {
//            float value = (Float) animation.getAnimatedValue();
            switch (animateState) {
                case ANIMATE_STATE_PENDING_SETTLE:
                case ANIMATE_STATE_PENDING_RESET:
                    break;
                case ANIMATE_STATE_PENDING_DRAG: {
//                    viewState.checkedLineColor = (int) argbEvaluator.evaluate(
//                            value,
//                            beforeState.checkedLineColor,
//                            afterState.checkedLineColor
//                    );

                    viewState.radius = beforeState.radius
                            + (afterState.radius - beforeState.radius) * value;

                    if (animateState != ANIMATE_STATE_PENDING_DRAG) {
                        viewState.buttonX = beforeState.buttonX
                                + (afterState.buttonX - beforeState.buttonX) * value;
                    }
                    viewState.checkStateColor = checkedColor;
//                    viewState.checkStateColor = (int) argbEvaluator.evaluate(
//                            value,
//                            beforeState.checkStateColor,
//                            afterState.checkStateColor
//                    );

                    break;
                }
                case ANIMATE_STATE_SWITCH: {
                    viewState.buttonX = beforeState.buttonX
                            + (afterState.buttonX - beforeState.buttonX) * value;

                    float fraction = (viewState.buttonX - buttonMinX) / (buttonMaxX - buttonMinX);

//                    viewState.checkStateColor = (int) argbEvaluator.evaluate(
//                            fraction,
//                            uncheckColor,
//                            checkedColor
//                    );
                    viewState.checkStateColor = checkedColor;
                    viewState.checkedLineColor = checkLineColor;

                    viewState.radius = fraction * viewRadius;
//                    viewState.checkedLineColor = (int) argbEvaluator.evaluate(
//                            fraction,
//                            Color.TRANSPARENT,
//                            checkLineColor
//                    );
                    break;
                }
                default:
                case ANIMATE_STATE_DRAGING:
                case ANIMATE_STATE_NONE: {
                    break;
                }
            }
            invalidate();
        }
    };

    private AnimatorGroup.StateChangedListener animatorListener
            = new AnimatorGroup.StateChangedListener() {
        @Override
        public void onStart(Animator animator) {

        }

        @Override
        public void onStop(Animator animator) {

        }

        @Override
        public void onCancel(Animator animator) {

        }

        @Override
        public void onEnd(Animator animator) {
            switch (animateState) {
                case ANIMATE_STATE_PENDING_DRAG: {
                    animateState = ANIMATE_STATE_DRAGING;
                    viewState.checkedLineColor = Color.TRANSPARENT.getValue();
                    viewState.radius = viewRadius;

                    invalidate();
                    break;
                }
                case ANIMATE_STATE_PENDING_RESET: {
                    animateState = ANIMATE_STATE_NONE;
                    invalidate();
                    break;
                }
                case ANIMATE_STATE_PENDING_SETTLE: {
                    animateState = ANIMATE_STATE_NONE;
                    invalidate();
                    broadcastEvent();
                    break;
                }
                case ANIMATE_STATE_SWITCH: {
                    isChecked = !isChecked;
                    animateState = ANIMATE_STATE_NONE;
                    invalidate();
                    broadcastEvent();
                    break;
                }
                case ANIMATE_STATE_DRAGING:
                    break;
                default:
                case ANIMATE_STATE_NONE: {
                    break;
                }
            }
        }

        @Override
        public void onPause(Animator animator) {

        }

        @Override
        public void onResume(Animator animator) {

        }
    };


    /*******************************************************/
    /**
     * 保存动画状态
     */
    private static class ViewState {
        /**
         * 按钮x位置[buttonMinX-buttonMaxX]
         */
        float buttonX;
        /**
         * 状态背景颜色
         */
        int checkStateColor;
        /**
         * 选中线的颜色
         */
        int checkedLineColor;
        /**
         * 状态背景的半径
         */
        float radius;

        ViewState() {
        }

        private void copy(ViewState source) {
            this.buttonX = source.buttonX;
            this.checkStateColor = source.checkStateColor;
            this.checkedLineColor = source.checkedLineColor;
            this.radius = source.radius;
        }
    }

}
